#include "account_service.h"
#include "context.h"
#include "streamdata.h"
#include "log.h"
#include "util.h"
#include "gameapi.pb.h"
#include "1700_login.pb.h"
#include "1700_account.pb.h"


// static bool __init__ = AccountService::Instance()->Init();

bool AccountService::Init()
{
    Ctx.msg_router.BindMsg(account_proto::ACCOUNT_CMD_VERIFY_LOGIN_TOKEN_RESP, std::bind(&AccountService::OnAuth, this, std::placeholders::_1));
    Ctx.msg_router.BindMsg(account_proto::ACCOUNT_CMD_GET_ACCOUNT_RESP, std::bind(&AccountService::OnGetAccount, this, std::placeholders::_1));

    return true;
}

bool AccountService::HandleAuth(Sence sence, const std::string& token, std::string&& trans)
{
    log_debug("enter,sence:%d,token:%s", sence, token.c_str());
    StreamData stream_data;
    StreamDataWriter write(stream_data);
    write.Write<Sence>(sence);
    write.WriteInt64(CTools::GetUnixTimeMs());
    write.WriteString(std::move(trans));

    account_proto::VerifyLoginTokenReq req;
    req.set_token(token);
    req.set_trans(std::move(stream_data.Data()));

    log_debug("req:%s", req.ShortDebugString().c_str());
    return 0 == Ctx.host->MtSendtoSrv(account_proto::ACCOUNT_CMD_VERIFY_LOGIN_TOKEN_REQ, SERVER_TYPE_ACCOUNT, &req, 0);
}

void AccountService::OnAuth(MsgData&& data)
{
    log_debug("enter");
    do
    {
        account_proto::VerifyLoginTokenResp resp;
        if (!resp.ParseFromArray(data.data.c_str(), data.data.size()))
        {
            log_error("parser account_proto::VerifyLoginTokenResp failed, stype:%hu,svid:%u,uuid:%d", data.svtype, data.svid, data.uuid);
            break;
        }

        StreamData stream_data(std::move(*resp.mutable_trans()));
        StreamDataReader reader(stream_data);
        Sence sence = reader.Read<Sence>();
        std::uint64_t req_time = reader.ReadInt64();
        std::string trans = reader.ReadString();

        std::uint64_t resp_time = CTools::GetUnixTimeMs();
        std::uint64_t cost_time = resp_time-req_time;
        if (cost_time > 50000) log_warning("uid:%u gen token cost %lu us", resp.uid(), cost_time);
        else log_debug("uid:%u gen token cost %lu us", resp.uid(), cost_time);

        auto it = m_auth_listen.find(sence);
        if (it == m_auth_listen.end())
        {
            log_info("sence:%d not listen, stype:%hu,svid:%u,uuid:%d", sence, data.svtype, data.svid, data.uuid);
            break;
        }
        try
        {
            int err = 0;
            std::string errmsg = "";
            stUserSession* psession = nullptr;

            if (resp.result() == 0)
            {
                stUserSession user_session;
                user_session.uid = resp.uid();
                user_session.agency_id = resp.agency_id();
                user_session.agency = resp.agency();
                user_session.username = resp.username();
                user_session.currency = resp.currency();
                user_session.currency_unit_multi = resp.currency_unit_multi();
                user_session.currency_label = resp.currency_label();
                user_session.token = resp.token();
                user_session.balance = resp.balance();
                user_session.hall_url = resp.hall_url();
                user_session.platform = resp.platform();

                Json::Value gameinfo_json;
                if (CTools::FromStr(gameinfo_json, resp.gameinfo()))
                {
                    if (gameinfo_json.isMember("fullscreen") && gameinfo_json["fullscreen"].isString())
                    {
                        user_session.fullscreen = gameinfo_json["fullscreen"].asString();
                    }
                    if (gameinfo_json.isMember("lang") && gameinfo_json["lang"].isString())
                    {
                        user_session.lang = gameinfo_json["lang"].asString();
                    }
                    if (gameinfo_json.isMember("extern_json") && gameinfo_json["extern_json"].isString())
                    {
                        user_session.ext = gameinfo_json["extern_json"].asString();
                    }
                }
                psession = UserSessionMgr::Instance()->Update(std::move(user_session));
            }
            else
            {
                err = gameapi::ErrorCode::AbnormalErr;
                errmsg = std::to_string(resp.result());
            }
            it->second(err, std::move(errmsg), psession, std::move(trans));
        }
        catch(const std::exception& e)
        {
            log_error("catch exception:%s, sence:%d, stype:%hu,svid:%u,uuid:%u,msg:%s", e.what(), sence, data.svtype, data.svid, data.uuid, resp.ShortDebugString().c_str());
        }
        catch(...)
        {
            log_error("catch unknown exception, sence:%d, stype:%hu,svid:%u,uuid:%u,msg:%s", sence, data.svtype, data.svid, data.uuid, resp.ShortDebugString().c_str());
        }
    } while(false);
}

bool AccountService::HandleGetAccount(Sence sence,  std::uint32_t uid, std::string&& trans)
{
    log_debug("enter,sence:%d,uid:%u", sence, uid);
    StreamData stream_data;
    StreamDataWriter write(stream_data);
    write.Write<Sence>(sence);
    write.WriteInt64(CTools::GetUnixTimeMs());
    write.WriteString(std::move(trans));

    account_proto::GetAccountReq req;
    req.set_uid(uid);
    req.set_trans(std::move(stream_data.Data()));

    log_debug("req:%s", req.ShortDebugString().c_str());
    return 0 == Ctx.host->MtSendtoSrv(account_proto::ACCOUNT_CMD_GET_ACCOUNT_REQ, SERVER_TYPE_ACCOUNT, &req, 0);
}
void AccountService::OnGetAccount(MsgData&& data)
{
    log_debug("enter");
    do
    {
        account_proto::GetAccountResp resp;
        if (!resp.ParseFromArray(data.data.c_str(), data.data.size()))
        {
            log_error("parser account_proto::GetAccountResp failed, stype:%hu,svid:%u,uuid:%d", data.svtype, data.svid, data.uuid);
            break;
        }

        StreamData stream_data(std::move(*resp.mutable_trans()));
        StreamDataReader reader(stream_data);
        Sence sence = reader.Read<Sence>();
        std::uint64_t req_time = reader.ReadInt64();
        std::string trans = reader.ReadString();

        std::uint64_t resp_time = CTools::GetUnixTimeMs();
        std::uint64_t cost_time = resp_time-req_time;
        if (cost_time > 50000) log_warning("uid:%u gen token cost %lu us", resp.uid(), cost_time);
        else log_debug("uid:%u gen token cost %lu us", resp.uid(), cost_time);

        auto it = m_auth_listen.find(sence);
        if (it == m_auth_listen.end())
        {
            log_info("sence:%d not listen, stype:%hu,svid:%u,uuid:%d", sence, data.svtype, data.svid, data.uuid);
            break;
        }
        try
        {
            int err = 0;
            std::string errmsg = "";
            stUserSession* psession = nullptr;

            if (resp.err_code() == 0)
            {
                stUserSession user_session;
                user_session.uid = resp.uid();
                user_session.agency_id = resp.agency_id();
                user_session.agency = resp.agency();
                user_session.username = resp.username();
                user_session.currency = resp.currency();
                user_session.currency_unit_multi = resp.currency_unit_multi();
                user_session.currency_label = resp.currency_label();
                user_session.token = resp.token();
                user_session.balance = 0;        // 无缓存回调 余额置0
                user_session.hall_url = resp.hall_url();
                user_session.platform = resp.platform();

                Json::Value gameinfo_json;
                if (CTools::FromStr(gameinfo_json, resp.gameinfo()))
                {
                    if (gameinfo_json.isMember("fullscreen") && gameinfo_json["fullscreen"].isString())
                    {
                        user_session.fullscreen = gameinfo_json["fullscreen"].asString();
                    }
                    if (gameinfo_json.isMember("lang") && gameinfo_json["lang"].isString())
                    {
                        user_session.lang = gameinfo_json["lang"].asString();
                    }
                    if (gameinfo_json.isMember("extern_json") && gameinfo_json["extern_json"].isString())
                    {
                        user_session.ext = gameinfo_json["extern_json"].asString();
                    }
                }
                psession = UserSessionMgr::Instance()->Update(std::move(user_session));
            }
            else
            {
                err = gameapi::ErrorCode::AbnormalErr;
                errmsg = std::to_string(resp.err_code());
            }
            it->second(err, std::move(errmsg), psession, std::move(trans));
        }
        catch(const std::exception& e)
        {
            log_error("catch exception:%s, sence:%d, stype:%hu,svid:%u,uuid:%u,msg:%s", e.what(), sence, data.svtype, data.svid, data.uuid, resp.ShortDebugString().c_str());
        }
        catch(...)
        {
            log_error("catch unknown exception, sence:%d, stype:%hu,svid:%u,uuid:%u,msg:%s", sence, data.svtype, data.svid, data.uuid, resp.ShortDebugString().c_str());
        }
    } while(false);
}
























